#pragma once

#include <iostream>
#include <memory>
#include <string>
#include <sstream>
#include <jsoncpp/json/json.h>
#include <jsoncpp/json/writer.h>  
// #define SelfDefine 1


namespace Protocol{

const std::string ProtSep = " ";
const std::string LineBreak = "\n";


//可以在这里encode，再加一个选择去选择协议
std::string Encode(const std::string &msg)
{
    std::string  length = std::to_string(msg.size());
    return length+LineBreak +msg +LineBreak;
}

//不是绝对保证是完整的报文，因此需要在这里处理
bool Decode(std::string& package,std::string* msg)
{
    auto Sep = package.find(LineBreak);
    if(Sep == std::string::npos) return 0;
    std::string lens = package.substr(0,Sep);
    unsigned long long int msgLen = std::stoull(lens);

    unsigned long long total = lens.size()+ msgLen + 2* LineBreak.size();
    if(package.size()<total) return 0;
    *msg = package.substr(Sep+1,msgLen);
    package.erase(0,total);
    return 1;
}
class Request{
    public:
    Request()
    :_data_x(0)
    ,_data_y(0)
    ,_data_oper(0)
    {
        
    }
    Request(double x,double y,char op)
    :_data_x(x)
    ,_data_y(y)
    ,_data_oper(op)
    {
        
    }
    void Debug()
    { 
        std::cout<<"Data x:"<<_data_x<<"\nData y:"<<_data_y<<std::endl;
    }
    bool Serialisze(std::string *out)
    {  
#ifdef SelfDefine 
        *out= std::to_string(_data_x)+ ProtSep +_data_oper+ProtSep+ std::to_string(_data_x); 
        return 1;
#else
        Json::Value root;
        root["datax"] = _data_x;
        root["datay"] = _data_y;
        root["oper"] = _data_oper;

        Json::OStringStream jos;
        jos<<root;
        *out = jos.str();
        return 1;
#endif

    }
    bool Deserialize(const std::string &in)//x op y
    {
#ifdef SelfDefine 
        auto left = in.find(ProtSep);
        auto right = in.rfind(ProtSep);
        if(left == std::string::npos || right== std::string::npos || right-left!=2)
        {
            return 0;
        }
        _data_x = std::stod(in.substr(0,left));
        _data_y = std::stod(in.substr(right));
        _data_oper = in[left+1];
        return 1;
#else
        Json::Value root;
        Json::IStringStream jiss(in);
        jiss>>root;
        _data_x = root["datax"].asDouble();
        _data_y = root["datay"].asDouble();
        _data_oper = root["oper"].asInt();
        return 1;
#endif
    }
    double& GetX()
    {
        return _data_x;
    }
    double& GetY()
    {
        return _data_y;
    }
    char& GetOP()
    {
        return _data_oper;
    }
    private:
    //len\n 表示长度
    //x op y\n  表示表达式，表达式认为传输包含x op y
    double _data_x;
    double _data_y;
    char _data_oper;

};


class Response{
    double _result;
    int _code;
    public:
    Response()
    :_result(0)
    ,_code(0)
    {

    }
    Response(double result,int code)
    :_result(result)
    ,_code(code)
    {

    }
    bool Serialisze(std::string *out)
    {
#ifdef SelfDefine 
        *out = std::to_string(_result) + ProtSep + std::to_string(_code);
        return 1;
#else
        Json::Value root;
        root["result"] = _result;
        root["code"] = _code;
        Json::OStringStream jos;
        jos<<root;
        *out=jos.str();
        return 1;
#endif
    }
    bool DeSerialisze(const std::string &in)
    {
#ifdef SelfDefine 
        auto space = in.find(ProtSep);
        if(space==std::string::npos) return 0;
        _result = std::stod(in.substr(0,space));
        _code  = std::stod(in.substr(space+1));
        return 1;
#else
    Json::Value root;
    Json::IStringStream Jiss(in);
    Jiss>>root;
    _result = root["result"].asDouble();
    _code  = root["code"].asInt();
    return 1;

#endif
    }
    void SetResult(double result)
    {
        _result = result;
    }
    void SetCode(int code)
    {
        _code = code;
    }
    double GetResult()const
    {
        return _result;
    }
    int GetCode()const
    {
        return _code;
    }
};



class Factory{

public:
    std::shared_ptr<Request> BuildRequest()
    {
        return std::make_shared<Request>();
    }
    std::shared_ptr<Request> BuildRequest(double x,double y,char op)
    {
        return std::make_shared<Request>(x,y,op);
    }

    std::shared_ptr<Response> BuildReponse()
    {
        return std::make_shared<Response>();
    }
    std::shared_ptr<Response> BuildResponse(double result,int code)
    {
        return std::make_shared<Response>(result,code);
    }
};
};